package io.plus.server;

import drds.common.$;
import io.plus.interactive.Node;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.StandardSocketOptions;
import java.nio.channels.AsynchronousChannelGroup;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.util.concurrent.TimeUnit;

@Slf4j
@Data
public class Server {
    private ServerConfiguration serverConfiguration;
    private AsynchronousServerSocketChannel asynchronousServerSocketChannel;
    private AsynchronousChannelGroup asynchronousChannelGroup = null;
    private Node serverNode;
    private boolean isWaitingStop = false;

    public Server(ServerConfiguration serverConfiguration) {
        super();
        this.serverConfiguration = serverConfiguration;
    }


    public void start(String serverIp, int serverPort) throws IOException {
        this.serverNode = new Node(serverIp, serverPort);
        asynchronousChannelGroup = AsynchronousChannelGroup.withThreadPool(serverConfiguration.groupThreadPoolExecutor);
        asynchronousServerSocketChannel = AsynchronousServerSocketChannel.open(asynchronousChannelGroup);
        asynchronousServerSocketChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
        asynchronousServerSocketChannel.setOption(StandardSocketOptions.SO_RCVBUF, 64 * 1024);

        InetSocketAddress inetSocketAddress = null;
        if ($.isNullOrEmpty(serverIp)) {
            inetSocketAddress = new InetSocketAddress(serverPort);
        } else {
            inetSocketAddress = new InetSocketAddress(serverIp, serverPort);
        }
        asynchronousServerSocketChannel.bind(inetSocketAddress, 0);
        //
        AcceptCompletionHandler acceptCompletionHandler = serverConfiguration.getAcceptCompletionHandler();
        asynchronousServerSocketChannel.accept(this, acceptCompletionHandler);
        serverConfiguration.startTime = System.currentTimeMillis();
    }

    public boolean stop() {
        isWaitingStop = true;

//
        try {
            asynchronousServerSocketChannel.close();
        } catch (Exception e) {
            log.error("asynchronousServerSocketChannel.unbind()时报错", e);
        }
        try {
            asynchronousChannelGroup.shutdownNow();
        } catch (Exception e) {
            log.error("asynchronousChannelGroup.shutdownNow()时报错", e);
        }


        try {
            serverConfiguration.groupThreadPoolExecutor.shutdown();
        } catch (Exception e) {
            log.error(e.toString(), e);
        }
        try {
            serverConfiguration.lockCapableTaskThreadPoolExecutor.shutdown();
        } catch (Exception e) {
            log.error(e.toString(), e);
        }

        serverConfiguration.setStopped(true);
        boolean ok = true;
        try {
            ok = ok && serverConfiguration.groupThreadPoolExecutor.awaitTermination(6000, TimeUnit.SECONDS);
            ok = ok && serverConfiguration.lockCapableTaskThreadPoolExecutor.awaitTermination(6000, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            log.error(e.getLocalizedMessage(), e);
        }

        log.info(this.serverNode + " stopped");
        return ok;
    }


}
